/** @jsxImportSource @emotion/react */
//InputDatalist 替换 ComboBoxDatalist；
import * as React from "react";
import {useContext} from "react";
import {
    Button, CheckSwitch,
    CommitInput,
    Container,
    IconArrowRight,
    InputLine,
    LineColumn,
    Select,
    Text,
    TextArea,
    useTheme
} from "customize-easy-ui-component";
import useFlowToMutation from "../hook/useFlowRequestMutation";
import {OneUserChoose} from "../../common/user/OneUserChoose";
import RoutingContext from "../../routing/RoutingContext";
import UserContext from "../../routing/UserContext";
import {ChooseEqps} from "../../comp/ChooseEqps";
import {css} from "@emotion/react";
import {mutiSelectedArr} from "../../common/tool";
import {设备种类} from "../../dict/eqpComm";
import {EqpsParamModify} from "./EqpsParamModify";
import {useLazyLoadQuery} from "react-relay/hooks";
import {TechnicalFieldQuery$data} from "./__generated__/TechnicalFieldQuery.graphql";

import {ChoosePipingUnits} from "../../comp/ChoosePipingUnits";
import {关键参数typec} from "./editParamConfig";

const graphql = require("babel-plugin-relay/macro");
const TechnicalFieldQuery = require('./__generated__/TechnicalFieldQuery.graphql');


export const 延期理由s=["已检正在出具检验报告","已约定检验时间","已上报监察机构","手工报告单上报监察机构","正在确认未检原因","设备状态已变更未提交变更申请",
    "因保温层未拆除或流动式起重机无法实施检验","备用锅炉或季节性使用锅炉","其它"];
export const 取消理由s=["任务生成错误","客户申请撤销","协议取消","其它"];



interface Props {
    readOnly?: boolean;
    editable?: boolean;
    req?:any;
    mutationFunc: (...args: any[]) => any;
    curFlow?:any;
}
/**关键技术参数变更后推送申请。 管道单元特别；
 * 一关卡审核模式：
 * 第二步保存按钮才能够修改申请单的：各个设备单元的各个参数旧的取值以及申请变更新取值，没法保存申请单的话，再次点击获取本平台最新取值按钮就不具备破坏力了:旧取值?=本平台最新值。
 * 多一个按钮，【考虑】申请单已结束基本完成的状态之后：把按钮改造成，获取最新值并且和申请单变更目标值进行对比，发现不同点。校验全部变更结果？按钮、
 * 这里管道单元多选实际存储像：{"devs": [ {"crDate": "2023-08-07", "id": "Ank7qJ_vSim2WfEbVKjSvlBpcGluZ1VuaXQ"} ,],}这样的，后端数据库的模型+ID。
 * */
export const TechnicalField: React.FunctionComponent<Props> = (
    {
       readOnly,
       editable,
       req=null,    //申请单，从数据库获得
      mutationFunc,
        curFlow,
     }) =>
{
  //这个位置就应该体现解析graphQL内省的json集合字段：data:{}从string变身对象。
    const theme = useTheme();
    const { history } = useContext(RoutingContext);
    const {save, field, reurl}= window.history.state?.state??{};      //通用伪对话框传递格式:save是编辑器保存的。
    //假如从多选选定设备页面返回的："移出多选集" : "加入多选集" 操作过后，将会导致save.devs[]对象变身成了设备页面的经过SessionStorage倒腾一手的对象。
    const edt = save?  save : req;
    //若从save恢复的，confirm已经解析为对象Object:【可能从伪对话框返回】
    let  dat = edt?.dat instanceof Object?  edt?.dat : JSON.parse(edt?.dat || '{}');
    //后端数据库当前储存版本的【容易混淆逻辑】
    const  datDB = req?.dat && JSON.parse(req?.dat || '{}');
    const [理由, set理由] = React.useState(dat?.理由);
    //【琢磨】仅仅存在于短期流程活动使用的需要结构化吗？成本和收益对比？,本来应当是关联对象的却被非结构化，graphQL没办法内省的，片段快照某些关键字段？？
    //非结构化关联对象的和正常JPA关联对象的优缺点对照： 前者适合于频繁新增删除的，关系生存时间短暂的，后端基本不参与计算的。
    //因为ChooseEqps对话框选择设备之后返回的实际数据字段通常是save.devs而不是我这非结构化json存储到了dat:{devs{[]}}，所以需要转换 #前提条件save?.devs表示挑选设备列表伪对话框之后调回来的。
    const [devs, setDevs] = React.useState(save?.devs? save.devs : dat?.devs);

  //   const curFlow=sessionStorage['审批单']&&JSON.parse(sessionStorage['审批单']);
    const {call:flowToFunc,doing:flowing, called:flowed, reset:flowreset}=useFlowToMutation();
    //第二关批准人，或者唯一关的审核人； 语义上问题：若2关口的话那么打印发放人员反而是通常意义的最终核准人了, 别扭，通用申请单想要统一语义？通用申请单过滤统计用处不大?。
    const [auditor, setAuditor] = React.useState<any>(req?.auditor);
    const [director, setDirector] = React.useState<any>(req?.director);
    //有2关审批的算是第1关的审核人；
    const [manager, setManager] = React.useState<any>(req?.manager);
    const {user} = useContext(UserContext);
    const  audat = JSON.parse(edt?.audat || '{}');
    const [memo, setMemo] = React.useState<string|undefined>(audat?.memo);
    const  drdat = JSON.parse(edt?.drdat || '{}');
    const [drmemo, setDrmemo] = React.useState<string|undefined>(drdat?.memo);
    const  mndat = JSON.parse(edt?.mndat || '{}');
    const [mnmemo, setMnmemo] = React.useState<string|undefined>(mndat?.memo);
    const [paramx, setParamx] = React.useState<string[]>(dat?.paramx);
    const [eqpType, setEqpType] = React.useState((dat?.eqpType) || '4');
    const [pipe, setPipe] = React.useState<boolean|undefined>((dat?.pipe) || false);
    const floUrl='/request/'+ req?.id;
    const commitBlurRef =React.useRef<HTMLDivElement | null>(null);


    //申请变更之前的参数取值，保存按钮点击时出发修改。每一组参数：每个设备独立的； 实际是二维数据的[][] 类比allmp;
    const [oldpars, setOldpars] = React.useState<any[]>((save? save.oldpars : dat?.oldpars) || []);

    const paramlist = 关键参数typec[pipe? 'PU' : eqpType];

    let devpipids=devs?.map((eqp: { id: any; })=>eqp.id);
    //useQueryLoader()和usePreloadedQuery没法放入同一个组件;Rendered more hooks than during the previous render.只能上下级嵌套组件
    // const [queryReference, loadQuery] = useQueryLoader(TechnicalFieldQuery);
    //正常loadQuery useQueryLoader必须嵌套组件，否则HOOK报错。
    //@不想嵌套组件的话，$就只能用不推荐模式：fetch a GraphQL query during render，性能较差，延迟大，render同时数据再次调整就会render多次。但relay缓存过的就不会重复查。
    const data = useLazyLoadQuery<typeof TechnicalFieldQuery>(
        graphql`
            query TechnicalFieldQuery($ids: [ID]) {
                modelNodes(ids: $ids) {
                    id,
                    ... on Equipment {
                        oid,cod,type,sort,vart,subv,svp,pa,crDate
                    }
                    ... on Elevator {
                        flo,spec,nnor,oldb,vl,hlf,lesc,wesc,cpm,tm,mtm,buff,
                        rtl,aap,prot,doop,limm,opm,lbkd,nbkd
                    }
                    ... on Boiler {
                        wall,power,form,fuel,pres,bmod,asemb
                    }
                    ... on Crane {
                        hlf,hlfm,nnor,vls,flo,tm,cpm,opm,rtlf,cap,rvl,mvl,cvl,scv,
                        lmv,rtv,luff,ns,pnum,rang,span,two,twoc,grab,suck,cotr,
                        walk,mom,whole,tno,cpi,pcs,pcw,miot,luf,jobl,highs,part,
                        occa,metl,level,auxh,wjib,
                    }
                    ... on Vessel {
                        vol,prs,pnum,highs,weig,rtlf,fulw,mdi,jakm,form,insul,mont,
                    }
                    ... on FactoryVehicle {
                        rtlf,mtm,pow
                    }
                    ... on Amusement {
                        level,mbig,leng,high,hlf,pnum,vl,sdia,grad,angl
                    }
                    ... on Pipeline {
                        level,matr,mdi,prs,temp
                    }
                    ... on PipingUnit {
                        pipe{id,cod,oid,useu{id,name}}, rno,code,reg,ust,proj,name,leng,start,stop,dets{id},crDate,nxtd1,nxtd2
                    }
                    __typename
                }
            }
        `,
        {ids: devpipids},
        {fetchPolicy: 'store-or-network'},
    );

    //有必要？做个 ES搜索引擎 索引，就是给no报告号的搜索加速？？
    const { modelNodes: devpis1 }=data ||{} as TechnicalFieldQuery$data;
    //把devpis.svp转换成对象再塞给devpis; 后续用到devpis的地方模型字段svp就不在是json了，svp已从string变身对象。json提前就转!
    const devpis =React.useMemo(() => {
        //这个?.__typename来区分到底是普通Eqp还是PipingUnit; 管道单元用rno替代cod做设备关键字。
        return devpis1?.map((devp: { svp: string; }, i: number) => {
                const  svp = JSON.parse(devp?.svp || '{}');       //关键字段变更参数应当不会出现在.pa{json}当中的,省略。
                return  {...devp, svp};
            }
        );
    }, [devpis1]);
    const [step, setStep] = React.useState<number>((save? save.step : dat?.step) || 1);
    //每一组参数：新的参数取值：每个设备独立的；
    const [allmp, setAllmp] = React.useState<any[]>((save? save.allmp : dat?.allmp) || []);
    //为了修改可以在React页面立刻同步显示需要的，不能直接修改原数组对象。 腾挪dat?.devs到了ispdvs：受编辑器控制的
    //不需要0所以下面的<InputPure type="number" value={ fseq || ''}，若要0取值的要改成value={ fseq || '0'}才能显示为0的。
    //【注意】Select组件必须加上<option></option>否则默认第一条,后端可能根本就没有数据 也显示默认第一条。
    //【关键】字段：在首次发起流程或者退回到编制申请重新提交时刻，send取值决定了BPMN的审批是2层的还是1层审批人的。
    async function confirmation() {
        //【前提条件】devs和paramx俩个数组的各自的顺序不能随意变化，oldpars，allmp这两个实际和他们是强制关联的，二维数组结构！！
        // const{使用单, 服务单, 设备种}= dat;
        //正好对应了后端内部class EqpTechnicalFieldDat{}，后端参与非结构化内容利用;
        const newdat={
            dat: {
                理由, eqpType, pipe, devs, paramx, oldpars, allmp, step,
            },
        };
        //伪对话框跳转恢复也会用到的。
        return newdat;
    }
    console.log("devpisz这里是本平台台账最新看见值=",devpis,"变更",allmp);
    // let mmvars=paramx?.map((param,i) => {
    //     const {view: selectDevsDialog,eqpparvls}= useEqpsParamModify({
    //         eqsum: 3,
    //     });
    //     React.useEffect(() => {
    //         let obnew= allmp[i];        //对应某一个参数的坑。
    //         obnew= eqpparvls;
    //         allmp.splice(i, 1, obnew);
    //         // setAllmp([eqpparvls]);
    //         setAllmp([ ...allmp ] );
    //         console.log("嵌套setAllmp组件=",allmp,"化￥=",eqpparvls);
    //     }, [eqpparvls, allmp, setAllmp, i]);
    //
    //     return(<div key={i}>
    //             {selectDevsDialog}
    //         </div>
    //     );
    // }  );

    //对应的已选定参数的中文名字: 要与paramx的顺序保证一致。
    const parmConfigs= paramx?.map((param,i) => {
        //单一配置项["工作级别（桥门/臂架）","jobl","WORKGRADE"],
        const ix=paramlist.findIndex((parmconfig:any) => parmconfig[1] === param);
        return paramlist[ix];
    });
    //默认是显示旧的也就是变更之前台账显示值，申请单保存时刻快照存储的旧的参数值，并非最新值！
    const [viewOld, setViewOld] = React.useState<boolean>(oldpars?.[0]!==undefined);
    //快照旧的参数取值。返回二维【某参数】【某设备】,要和 allmp 保持一致顺序。
    function oldParVals() {
        return paramx?.map((param, i) => {
            let svpZD = param.startsWith("svp.");
            let sparzd =svpZD? param.substring(4) : '';
            return devpis?.map((dev: { [x: string]: any; }, i: any) =>
                ( (svpZD? dev.svp[sparzd] : dev[param]) || '')
            );
        });
    }


    //因为中间步骤的参数编辑器受到前面的设备参数选择影响很大，所以必须分解连两个步骤，并且限定不可能只有修改前面步骤的已选定设备参数，避免复杂性和不可控性，否则有逻辑困境。
    return (
    <div
      css={{
        [theme.mediaQueries.md]: {
          height: "auto",
          display: "block"
        }
      }}
    >
      <Text
        css={{
          flex: 1,
          textAlign: "center",
          [theme.mediaQueries.md]: {
            textAlign: "left"
          }
        }}
        wrap={true}
        variant="h5"
        gutter={false}
      >
        审批通过后，可把本平台相应字段参数的已修订最新取值同步推送给相应的监察平台。
      </Text>

      <div
        css={{
          flex: 1,
          [theme.mediaQueries.md]: {
            flex: "none"
          }
        }}
      >
        <div>
          <Container>
            <div
              css={{
                paddingTop: theme.spaces.lg,
                paddingBottom: theme.spaces.lg
              }}
            >
                <Text variant="h6">第一步，事前先从监察平台拉取设备台账参数，验证本平台已和监察平台的台账同步，从而发现需要修改的参数:</Text>
                <Text>设备种类必须唯一，设备所属监察平台也必须相同的。</Text>
                <LineColumn column={3}>
                    <InputLine label={`是否选择管道单元:`}>
                        <CheckSwitch  checked= {pipe || false}  disabled={step!==1}
                                      onChange={e => {
                                          if(!pipe)  setEqpType("8");      //"8": "压力管道",
                                          setPipe(pipe? undefined:true);
                                      } }
                        />
                    </InputLine>
                    <InputLine label={`设备种类:`}>
                        <Select inputSize="md" css={{minWidth:'140px',fontSize:'1rem',padding:'0 1rem'}} divStyle={css`max-width:240px;`}
                                value={eqpType || ''}   disabled={pipe || step!==1}
                                onChange={e => {
                                    setEqpType( e.currentTarget.value);
                                    setParamx([]);
                                } }
                        >
                            {
                                Object.entries(设备种类).map(([key,value],i) => (
                                    <option key={i} value={key}>{value}</option>
                                ))
                            }
                        </Select>
                    </InputLine>
                    {pipe?
                        <InputLine label={`多个管道单元挑选(快照模式):`}>
                            <ChoosePipingUnits  field={'devs'}  jsoned={true}
                                                autoFocus={field==='devs'}
                                                onSetEqps={(all) => { setDevs(all) }}
                                                onDialog={async () => { return await confirmation() } }
                                                devices={devpis}
                                                orgDevs={datDB?.devs  as any}
                                                edit={step===1} />
                        </InputLine>
                      :
                        <InputLine label={`多个设备挑选(快照模式):`}>
                            <ChooseEqps  field={'devs'}  jsoned={true}
                                         autoFocus={field==='devs'}
                                         onSetEqps={(all) => { setDevs(all) }}
                                         onDialog={async () => { return await confirmation() } }
                                         devices={devpis}
                                         orgDevs={datDB?.devs  as any}
                                         edit={step===1} />
                        </InputLine>
                    }
                </LineColumn>

                <InputLine label={`关键参数(多选):`}>
                    <Select inputSize="md" divStyle={css`max-width:360px;`} multiple  value={ paramx }
                            disabled={step!==1}
                            css={{
                                minWidth:'190px',
                                fontSize:'1rem',
                                padding:'0 1rem',
                                height:'7rem',
                                [theme.mediaQueries.md]: {
                                    height:'13rem',
                                }
                            }}
                            onChange={e => {
                                setParamx(mutiSelectedArr(e));
                            } }
                    >
                        <option value={''}></option>
                        { paramlist.map(([name,field,mapfield]: any, i: React.Key | null | undefined) => {
                            return (
                                <option  key={i} value={field} css={{textWrap: 'wrap'}}>{name}</option>
                            );
                        })}
                    </Select>
                </InputLine>
                { (req?.status==='INIT') &&
                    <Button intent="primary" disabled={curFlow && !(curFlow?.entId === req?.id)}
                            onPress={async () => {
                                if(step===1){
                                    setStep(2);
                                    setOldpars(oldParVals());    //oldpars就在这保存
                                    setAllmp(oldParVals());    //这不能用setAllmp(oldpars);
                                }
                                else if(step===2)  setStep(1);
                            }}
                    >
                        { (step===1)? `第一步完成选择参数有${paramx?.length??0}个并保存参数取值快照` : '重新进入第一步挑选' }
                    </Button>
                }
                <Text variant="h6">第二步，提交要修改的{paramx?.length??0}组参数值以及证明材料理由，并同步推送监察平台:</Text>
                <LineColumn column={3}>
                    <InputLine label={`理由:`}>
                        <TextArea required rows={4}
                                  value={理由} onChange={e => set理由( e.currentTarget.value||undefined ) }
                        />
                    </InputLine>
                </LineColumn>
                <Button intent="primary" disabled={curFlow && !(curFlow?.entId === req?.id)}
                        onPress={async () => {
                            setViewOld(!viewOld);
                        }}
                >
                    { viewOld? '平台最新值和目标申请值对照' : '显示申请单时刻的参数取值快照' }
                </Button>

                { step!==1 && paramx?.map((param,i) => {
                    return(
                        <EqpsParamModify key={i} field={'devs'}  jsoned={true}
                                     autoFocus={field==='devs'}
                                         oldpars={oldpars}
                                         allmp={allmp}
                                         setAllmp={setAllmp}
                                         index={i}
                                         paramConf={parmConfigs[i]}
                                         devpis={devpis}
                                         viewOld={viewOld}
                                     onDialog={async () => { return await confirmation() } }
                                     orgDevs={edt?.devs  as any}
                                     edit={true}
                        />
                    );
                }  ) }


                {
                    (req?.status==='INIT') &&
                      <Button size="lg" intent="primary"  iconAfter={<IconArrowRight />}
                              css={{ marginTop: theme.spaces.sm, whiteSpace:'unset' }}
                              disabled={req?.status !== 'INIT'}
                        onPress={ async () => {
                            const sendInp=await confirmation();
                            //这里的inpDevs[]顺序千万不能变动，二维数组,设备和参数任意一个顺序变化，都只能清空旧的配置!
                            //【同步一致性】modelNodes()获取的有可能并不是上次保存所看见的那些管道单元，json{id}只有id不可靠，不是严格ACID事务。code:,rno没必要存储了
                            const inpDevs=sendInp.dat.devs?.map((a: any)=>{return {id:a?.id,
                                crDate:a?.crDate
                            };});
                            //没法把undefined发给后端；JSON.parse([,undefined,]);会报错，前端都不能接受。#@ 用undefined表示不做变更的思路失败！
                            //改变逻辑思路：？ 申请修改之前的取值和目标值一样的就是没有变更的，后端对于取值保持不变的就不会发送给监察平台做修改，免于覆盖可能被第三者修改的同步冲突。
                            const inpPreare={ ...sendInp,
                                dat: JSON.stringify({...sendInp.dat, devs:inpDevs, oldpars} )
                            };
                            //只有这里才可以变更oldpars, 快照以后就不再改了！
                            //前端数据模型是{"allmp": [], "devs": [], "eqpType": "4", "oldpars": [], "paramx": []}
                            await mutationFunc(req?.id, 'UPD', inpPreare);
                        } }
                      > 先保存申请资料
                      </Button>
                }
            </div>

              <InputLine label={'关键技术参数变更的审核人:'}>
                  { (req?.status==='INIT') ?
                      <OneUserChoose name={auditor?.person?.name!} setEditorVar={setAuditor}
                                 oobj={auditor}/>
                      :
                      <Text css={{textAlign: "left"}}>{auditor?.person?.name}</Text>
                  }
              </InputLine>

              { (req?.status==='INIT' || (curFlow && curFlow?.entId === req?.id && curFlow?.tdId==='request_author_modify') ) &&
                  <Button intent="primary" disabled={(curFlow && !(curFlow?.entId === req?.id) && req?.status!=='INIT') ||
                         ( !auditor ) }
                        onPress={async () => {
                             await flowToFunc(curFlow?.utId, req?.id,3,"", "YES",'关键技术参数变更申请:'+user?.person?.name,
                                  auditor?.id, floUrl, 20);
                              sessionStorage['审批单'] = null;
                              history.push(`/zeebeTodo`);
                        }}
                  >
                      { ((curFlow?.tdId==='request_author_modify')? '再提交申请' : '提交申请给审核人') }
                  </Button>
              }

              <Text variant="h6">第三步，审核人的审核情况：</Text>
              {  ((curFlow && curFlow?.entId === req?.id) || req?.status!=='INIT') &&
                  <InputLine label={`审核人的意见:`}>
                      { ((curFlow?.tdId==='request_auditor_opinion') || curFlow?.tdId==='request_manager_opinion') ?
                          <CommitInput  value={ memo || ''}  onSave={txt => setMemo( txt || undefined) }
                                        placeholder="如果拒绝或回退的，请给出理由"
                          />
                          :
                          <Text css={{textAlign: "left"}}>{ memo }</Text>
                      }
                  </InputLine>
              }


              { (curFlow?.entId === req?.id && (curFlow?.tdId==='request_auditor_opinion' ) ) &&
                  <>
                      <Button intent="primary" disabled={curFlow && !(curFlow?.entId === req?.id)}
                              onPress={async () => {
                                  const opndat= req?.status==='INIT' ? '' :
                                      JSON.stringify( {memo} );
                                  await flowToFunc(curFlow?.utId, req?.id,3,opndat, "YES",":"+user?.person?.name,
                                      null , null, 15);
                                  sessionStorage['审批单'] = null;
                                  history.push(`/zeebeTodo`);
                              }}
                      >
                      {  '通过的允许推送监察' }
                      </Button>
                      {
                          (req?.status!=='INIT') &&
                          <>
                              <Button intent="primary" css={{marginLeft: theme.spaces.sm}}
                                      disabled={curFlow && !(curFlow?.entId === req?.id)}
                                      onPress={async () => {
                                          const opndat=JSON.stringify( {memo} );
                                          await flowToFunc(curFlow?.utId, req?.id,3,opndat, "NO",":"+user?.person?.name,
                                              auditor?.id, null, 20);
                                          sessionStorage['审批单'] = null;
                                          history.push(`/zeebeTodo`);
                                      }}
                              >
                                  { '审批不通过' }
                              </Button>
                              <Button intent="primary" css={{marginLeft: theme.spaces.sm}}
                                      disabled={curFlow && !(curFlow?.entId === req?.id)}
                                      onPress={async () => {
                                          const opndat=JSON.stringify( {memo} );
                                          await flowToFunc(curFlow?.utId, req?.id,3,opndat, "BACK",":"+user?.person?.name,
                                              auditor?.id, null, 20);
                                          sessionStorage['审批单'] = null;
                                          history.push(`/zeebeTodo`);
                                      }}
                              >
                                  { '退回' }
                              </Button>
                          </>
                      }
                  </>
              }

            { (curFlow?.entId === req?.id && (curFlow?.tdId==='request_deny' || curFlow?.tdId==='request_finish')) &&
                <>
              <Button intent="primary" disabled={curFlow && !(curFlow?.entId === req?.id)}
                      onPress={async () => {
                          await flowToFunc(curFlow?.utId, req?.id,1,'', "YES");
                          sessionStorage['审批单'] = null;
                          history.push(`/zeebeTodo`);
                      }}
              >
                {'知道了'}
              </Button>
                </>
            }

          { req?.status==='END' &&
                '恭喜，已经处理完结'
          }
              <Text variant="h6">不是监察平台管控的参数或设备，就不需要申请去同步给监察。</Text>
          </Container>
        </div>
      </div>

    </div>
  );
};


//多选框<Select multiple 使用，在浏览器的手机触摸屏形态下实际没必要预先去撑开太大,手机自动会弹出模态式，但是手机竖屏选择项一行的只能11个字符最多。单选模式手机可以自动换行显示的。
//JSX里面不能直接这样 <option  key={i} value={field} style="text-wrap: wrap;">{name}</option>添加css样式的，报错！改成<option css={{textWrap: 'wrap'}}的。
//但是这个样式加了以后仅仅谷歌浏览器模拟手机测试才有效，放在真实手机上却不生效的，估计和浏览器的对w3c实现有关。【结论】手机上<Select:多选每项不超过11个汉字为佳，单选模式无所谓。
//任何位置都不能[].map(=>{调用Hook})React Hook "useXxx" cannot be called inside a callback.Hooks must be called in a React function component or a custom React Hook!
